package de.fhd.pms.dao;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import de.fhd.pms.model.Automobil;
import de.fhd.pms.model.Fahrt;
import de.fhd.pms.model.Standort;
import de.fhd.pms.model.Teilnehmer;
//DOKUMENTATION FERTIG
/*
 * Schritt 6.1: DAO-Klasse als Unterklasse von HiberneteDaoSupport deklarieren
 */

/**
 * Dao Klasse für den Zugriff auf Automobile.
 * <p>
 * Die Klasse AutomobilDao wird verwendet, um Persistenz bzw. den Zugriff auf eine Datenbank zu
 * gewährleisten, ohne spezielle datenbankabhängige Befehle (z.B. Oracle, MySQL) verwenden zu müssen.
 * 
 * @author Martin Schmid
 * @author Florian Schachner
 */
public class AutomobilDao extends HibernateDaoSupport {

	private static Logger log = Logger.getLogger(AutomobilDao.class);

	//Wird per Dependency-Injection durch das Spring-Framework gefüllt (Konfiguriert in application-context.xml)
	private FahrtDao fahrtDao = null;
	public void setFahrtDao(FahrtDao fahrtDao) {
		this.fahrtDao = fahrtDao;
	}
	
	
	/*
	 * Schritt 6.2: save-Methode deklarieren, der eine Automobilinstanz als
	 * Parameter übergeben erhält
	 */


	/**
	 * Speichert ein Automobil-Objekt persistent in der Datenbank.<br/>
	 * Diese Methode legt einen neuen Datensatz in der Datenbank an,
	 * sofern das jeweilige Automobil noch nicht in der Datenbank vorhanden ist.
	 * Befindet sich das spezifische Automobil bereits in der Datenbank, dann
	 * wird dieser Datensatz upgedated.
	 * 
	 * @param automobil - {@link Automobil}
	 * @return automobil - {@link Automobil}
	 * @author Martin Schmid
	 * @author Florian Schachner
	 */
	public Automobil save(Automobil automobil) {
		log.info("AUTOMOBILDAO: save()");
		HibernateTemplate template = getHibernateTemplate();
		template.saveOrUpdate(automobil);
		return automobil;
	}

	
	/**
	 * Findet ein spezifisches {@link Automobil} in der Datenbank.<br/>
	 * Diese Methode findet einen spezifischen Datensatz in der Automobil-Tabelle der Datenbank
	 * anhand der übergebenen Identifizierungsnummer (ID) des Automobils und liefert
	 * das gefundene {@link Automobil}-Objekt zurück.
	 * 
	 * @param id - {@link Integer} - Primärschlüssel des Automobils
	 * @return automobil - {@link Automobil}
	 * @author Martin Schmid
	 * @author Florian Schachner
	 */
	public Automobil findById(int id) {
		log.info("AUTOMOBILDAO: findById()");
		HibernateTemplate template = getHibernateTemplate();
		return (Automobil) template.get(Automobil.class, id);
	}

	
	/**
	 * Findet alle {@link Automobile} in der Datenbank.<br/>
	 * Diese Methode findet alle gespeicherten Automobile in der Datenbank
	 * und liefert eine Liste aller gefundenen Automobile-Objekte zurück.
	 * 
	 * @return result - {@link List}<{@link Automobil}>
	 * @author Martin Schmid
	 * @author Florian Schachner
	 */
	@SuppressWarnings("unchecked")
	public List<Automobil> findAll() {
		log.info("AUTOMOBILDAO: findAll()");
		HibernateTemplate template = getHibernateTemplate();
		@SuppressWarnings("rawtypes")
		List results = template.loadAll(Automobil.class);
		return results;
	}

	
	/**
	 * Findet alle freien {@link Automobile} in der Datenbank.<br/>
	 * Diese Methode findet alle gespeicherten Automobile in der Datenbank,
	 * die sich aktuell nicht in einer Fahrt befinden und für neue Fahrten
	 * verfügbar sind.
	 * und liefert eine Liste aller gefundenen Automobile-Objekte zurück.
	 * 
	 * @return alleFreien - {@link List}<{@link Automobil}>
	 * @author Martin Schmid
	 * @author Florian Schachner
	 */
	//Unterdrückt Warnmeldungen die beim Casten durch den Compiler entstehen
	@SuppressWarnings("unchecked")
	public List<Automobil> findFreie() {
		HibernateTemplate template = getHibernateTemplate();

		log.info("*** ALLE FREIEN AUTOMOBILE IM FUHRPARK ***");
		List<Automobil> alleFreien = template.find("from Automobil a where a.available = 1");

		return alleFreien;
	}	
	
	
	/**
	 * Löscht ein spezifisches {@link Automobil} aus der Datenbank.<br/>
	 * Diese Methode versucht ein spezifisches Automobil-Objekt aus der Datenbank zu löschen.
	 * Das Automobil kann nur dann gelöscht werden, wenn das Automobil noch keine Fahrten absolviert hat.
	 * Hat das zu löschende Automobil bereits eine Fahrt angetreten, ist ein Löschvorgang nicht mehr möglich und
	 * eine neue {@link AutomobilDeleteException} wird mit einer entsprechenden Meldung geworfen.
	 * @param automobil - {@link Automobil} zu löschendes Automobil
	 * @author Martin Schmid
	 * @author Florian Schachner
	 */
	public void delete(Automobil automobil) throws AutomobilDeleteException {
		log.info("AUTOMOBILDAO: delete()");
		HibernateTemplate template = getHibernateTemplate();
		
		Set<Fahrt> fahrtenVonAutomobil = fahrtDao.findByAutomobil(automobil);
		if (fahrtenVonAutomobil.size() == 0){
			template.delete(automobil);
		}
		else{
			String msg = "Leider kann das von Ihnen ausgewählte Automobil nicht gelöscht werden, da mit diesem Automobil bereits Fahrten absolviert wurden. " +
						 "Wenn Sie das Automobil in weiteren Fahrten nicht weiter verwenden möchten, dann setzen Sie den Status des Automobils manuell auf 'Automobil nicht verfügbar'.";
			throw new AutomobilDeleteException(msg);
		}
	}
}
